
var struct={
    databse:'name',
    version:1.0,
    sort:"next",//prev
    columns:{keyPath:'id',index:[{email:{unique:true}}]}
};

function fw4wdb(database,version,columns){
        return new (function(database,version,columns){
            struct.database = database; 
            struct.version = version;
            struct.columns = columns;
            var op = {
                'addAll':function(values){db_add(struct,values);},
                'add':function(values){db_add(struct,values);},
                'putAll':function(values){db_put(struct,values);},
                'put':function(values){db_put(struct,values);},
                'clear':function(values){db_clear(struct);},
                'del':function(key){db_del(struct,key);},
                'each':function(callback){db_each(struct,callback);},
                'index':function(key){return db_index(struct,key);}
            };  
            this.open = function(callback){
                struct.op = op;
                db_open(struct,function(struct){
                    callback(struct.op);
                });
            };
        })(database,version,columns);
}


if(typeof $ === 'function'){
   $.wdb = fw4wdb;
}

function db_deleteDB(database){
    if(!window.indexedDB){
        window.indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    }
    window.indexedDB.deleteDataBase(database);
}

function db_open(struct,callback){
    if(!window.indexedDB){
        window.indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    }
    if(struct.version == undefined || typeof struct.version != 'number'){
        console.error("version undefiend",typeof struct.version);
    }else{
        var request = window.indexedDB.open(struct.database,struct.version);
        request.onsuccess = function(event){
            struct.db = request.result;
            callback(struct);
            struct.db.close();
        };
        request.onerror=function(event){
            console.log("open error",event.target.errorCode);
        };
        request.onblocked=function(event){
            alert("Please close all other tabs with this site open!");
        };
        request.onupgradeneeded=function(event){
            var keyPath = {autoIncrement:true};
            if(struct.columns != undefined && struct.columns.keyPath != undefined){
                console.log("struct columns ",struct.columns.keyPath);
                keyPath = {'keyPath':struct.columns.keyPath};
            }
            var db = event.target.result;
            
            db.onversionchange = function(event) {
                db.close();
                console.log("A new version of this page is ready. Please reload!");
                window.location.href = window.location.href;
            };
            if(!db.objectStoreNames.contains(struct.database)){
                console.log("create table");
                var store = db.createObjectStore(struct.database,keyPath);
                if(struct.columns != undefined && struct.columns.index != undefined){
                    var index = struct.columns.index;
                    for(var i=0;i<index.length;i++){
                        var fields = index[i];
                        for(var field in fields){
                            console.log(field,fields[field]);
                            console.log("aaa",fields[field]);
                            store.createIndex(field,field,fields[field]);
                        }
                    }
                }
            }
        };
    }

}
function getTransaction(struct,type){
    return struct.db.transaction(struct.database,type).objectStore(struct.database);
}
function db_add(struct,values){
    var objectStore = getTransaction(struct,'readwrite');
    objectStore.oncomplete = function(event){}
    objectStore.onerror = function(event){}
    if(!Array.isArray(values)){
        values = [values]; 
    }
    var len = values.length;
    for(var i=0;i<len;i++){
        objectStore.add(values[i]);
    }
}
function db_put(struct,values){
    var objectStore = getTransaction(struct,'readwrite');
    objectStore.oncomplete = function(event){}
    objectStore.onerror = function(event){}
    if(!Array.isArray(values)){
        values = [values]; 
    }
    var len = values.length;
    for(var i=0;i<len;i++){
        objectStore.put(values[i]);
    }
}
function db_each(struct,callback){
    range(struct,struct.columns.keyPath,null,callback);
}
function db_del(struct,key){
    var objectStore = getTransaction(struct,"readwrite");
    objectStore.delete(key);
    objectStore.onsuccess = function(event){
        console.log("delete success");
    }
}
function db_clear(struct){
    var objectStore = getTransaction(struct,"readwrite");
    objectStore.clear();
    objectStore.onsuccess = function(event){
        console.log("clear success");
    }
}
function range(struct,key,range,callback){
    console.log("range:",key);
    IDBKeyRange.NEXT = struct.sort == undefined ? "next" : struct.sort;  // next | prev
    var objectStore = getTransaction(struct,'readonly');
    var index = objectStore.index(key);
    index.openCursor(range,IDBKeyRange.NEXT).onsuccess = function(event){
        var cursor = event.target.result;
        if(callback == undefined || typeof callback != 'function') return;
        if(!cursor) return;
        callback(cursor.value);
        cursor.continue();
    };
}
function db_index(struct,key){
    return {
        'eq':function(x){
           return {
             'range':function(callback){
                var keyRange = IDBKeyRange.only(x);
                range(struct,key,keyRange,callback);
             }
           };
        },
        'gt':function(x){
            return {
                'lt':function(y){
                    return {
                        'range':function(callback){
                           var keyRange = IDBKeyRange.bound(x,y,true,true);
                           range(struct,key,keyRange,callback);
                        }
                    };
                },
                'le':function(y){
                    return db_index(struct,key).le(y).gt(x);
                },
                'range':function(callback){
                    var keyRange = IDBKeyRange.lowerBound(x,true);
                    range(struct,key,keyRange,callback);
                }
            };
        },
        //lt
        'lt':function(x){
            return {
                'gt':function(y){
                    return db_index(struct,key).gt(y).lt(x);
                },
                'ge':function(y){
                    return db_index(struct,key).ge(y).lt(x);
                },
                'range':function(callback){
                   var keyRange = IDBKeyRange.upperBound(x,true);
                   range(struct,key,keyRange,callback);
                }
            };
        },
        //ge
        'ge':function(x){
            return {
                'lt':function(y){
                    return {
                        'range':function(callback){
                            var keyRange = IDBKeyRange.bound(x,y,false,true);
                            range(struct,key,keyRange,callback);
                        }
                    };
                },
                'le':function(y){
                    return {
                        'range':function(callback){
                            var keyRange = IDBKeyRange.bound(x,y);
                            range(struct,key,keyRange,callback);
                        }
                    };
                },
                'range':function(callback){
                    var keyRange = IDBKeyRange.lowerBound(x);
                    range(struct,key,keyRange,callback);
                }
            };
        },
        //le
        'le':function(x){
           return {
            'gt':function(y){
                return {
                    'range':function(callback){
                        var keyRange = IDBKeyRange.boud(y,x,true,false);
                        range(struct,key,keyRange,callback);
                    }
                };
            }, 
            'ge':function(y){
                return db_index(struct,key).ge(y).le(x);
            }, 
            'range':function(callback){
                var keyRange = IDBKeyRange.upperBound(x);
                range(struct,key,keyRange,callback);
            }
           };
        }
    };
}

